//
// Created by fanghr on 18-3-27.
//

#ifndef BINDER_USER_CPP_H
#define BINDER_USER_CPP_H

#include <cstddef>
#include <cstdint>

extern "C" {
#include "binder.h"
}
namespace binder_cpp {
    class io;

    class binder;

    class access;

    class io {
    private:
        friend class access;

        friend class binder;

        binder_io *bio;
    public:
        io(void *data, size_t maxdata, size_t maxobjects);

        io();

        explicit io(binder_io *);

        ~io();

        void put_obj(void *ptr);;

        void put_ref(uint32_t handle);

        void put_uint32(uint32_t n);

        void put_string16(const uint16_t *str);

        void put_string16_x(const char *_str);

        void put_data(const uint16_t *data, size_t size);

        void put_data_x(const char *data, size_t size);

        uint32_t get_uint32();

        uint16_t *get_string16(size_t *sz);

        uint16_t *get_data(size_t *sz);

        uint32_t get_ref();

    };

    class binder {
    private:
        friend class access;

        binder_state *bs;
    public:
        explicit binder(size_t mapsize);

        ~binder();

        int call(io &msg, io &reply, uint32_t target, uint32_t code);

        void done(io &msg, io &reply);

        void acquire(uint32_t target);

        void release(uint32_t target);

        void link_to_death(int32_t target, struct binder_death *death);
    };

    class access {
    public:
        static binder_io *get_binder_io(io &obj);

        static binder_state *get_state(binder &obj);

    public:
        access() = delete;

        access &operator=(access &)= delete;
    };

    class server {
    private:
        binder_state *bs;
    public:
        explicit server(binder &obj);

        int publish(uint32_t target, char *name, void *ptr);

        void loop(binder_handler func);

        int become_context_manager();
    };

    class client {
    private:
        binder_state *bs;
    public:
        explicit client(binder &obj);

        uint32_t lookup(uint32_t target, char *name);

        int call(io &msg, io &reply, uint32_t target, uint32_t code);

        void init_payload(io &obj, uint32_t strict_mode = 0);

        void init_payload(io &obj, uint32_t strict_mode, uint16_t *str);

        void init_payload(io &obj, uint32_t strict_mode, char *str);

        void init_payload(io &obj, uint32_t strict_mode, void *ptr);
    };
}

#endif //BINDER_USER_CPP_H
